'' --------------------------------------------------------------------------------------------------------------------------------------------------------------------
'' From:
'' http://blogs.msdn.com/mshneer/archive/2007/03/02/windows-installer-fails-on-vista-with-2869-error-code.aspx
'' http://www.shahine.com/omar/VSTOAddinsAndVista.aspx
'' http://msdn2.microsoft.com/en-us/library/aa368069.aspx
'' Since I had the same problems, I combined the 2 scripts, Aaron and Misha proposed to 1.
'' For those, who are not developers and try to install an existing Msi, just run the script on the msi:
'' cscript <path to the script> <path to the msi>
'' Here is the script, most of it is taken from Aarons post of setting the NoImpersonate-Flag:
'' prepare MSI-Files for use on Vista-Systems
'' Visual Studio forgot to include 2 things:
'' 1. Mark Custom Actions as NoImpersonate, otherwise an Security-Error results in Error 2869
'' 2. User-Exceptions in CustomActions are not shown. Instead a plain Error 2869 without description occurs.
'' Therefore Error-Message for this case has to be defined.
'' cscript NoImpersonate.vbs <msi-file>
'' Performs a post-build fixup of an msi to change all deferred custom actions (CA) to NoImpersonate
 
Option Explicit
'' Constant values from Windows Installer
Const msiOpenDatabaseModeTransact = 1
Const msiViewModifyInsert = 1
Const msiViewModifyUpdate = 2
Const msiViewModifyAssign = 3
Const msiViewModifyReplace = 4
Const msiViewModifyDelete = 6
Const msidbCustomActionTypeInScript = &H00000400
Const msidbCustomActionTypeNoImpersonate = &H00000800
Dim databaseFile
Dim installer : Set installer = Nothing
Dim database : Set database = Nothing
Dim sql
Dim View, Record
Dim openMode : openMode = msiOpenDatabaseModeTransact
On Error Resume Next
Call Main()

Sub Main()
	If WScript.Arguments.Length <> 1 Then
		Fail("Usage is: cscript " & WScript.ScriptName & " [msi file]")
	End If
	databaseFile = WScript.Arguments(0)
	'WScript.Echo(WScript.ScriptName & ": operating on file '" & databaseFile & "'")
	'' Instantiate Windows Installer object
	Set installer = WScript.CreateObject("WindowsInstaller.Installer") : CheckError
	'' Open the MSI database
	Set database = installer.OpenDatabase(databaseFile, openMode) : CheckError
	Proc1 : CheckError
	'Proc2 : CheckError
	If openMode = msiOpenDatabaseModeTransact Then 
		database.Commit
	End If
	WScript.Quit 0
End Sub

Sub Proc1()
	'' 1. problem: CustomActions in Vista have to run with NoImpersonate
	sql = "SELECT `Action`, `Type`, `Source`, `Target` FROM `CustomAction`"
	Set View = database.OpenView(sql) : CheckError
	View.Execute : CheckError
	Do
		Set Record = View.Fetch
		If Record Is Nothing Then Exit Do
		'typeVal = Record.IntegerData(2)
		If (Record.IntegerData(2) And msidbCustomActionTypeInScript) <> 0 Then
			'WScript.Echo "Here 1, Type=" & Record.IntegerData(2)
			Record.IntegerData(2) = Record.IntegerData(2) Or msidbCustomActionTypeNoImpersonate
			'WScript.Echo "Here 2, Type=" & Record.IntegerData(2)
			View.Modify msiViewModifyReplace, Record : CheckError
		End If
	Loop
	View.Close
End Sub

Sub Proc2()
	'' 2. problem: explicit format User-Errors, otherwise they are not visible in Vista, the User just sees Error 2869
	sql = "INSERT INTO `Error` (`Error`, `Message`) VALUES (1001, 'Error [1]: [2]')"
	Set View = database.OpenView(sql) : CheckError
	WScript.Echo "Here 2"
	View.Execute : CheckError
	WScript.Echo "Here 3"
	View.Close
End Sub

Sub CheckError
	Dim message, errRec
	If Err = 0 Then Exit Sub
	message = Err.Source & " " & Hex(Err) & ": " & Err.Description
	If Not installer Is Nothing Then
		Set errRec = installer.LastErrorRecord
		If Not errRec Is Nothing Then message = message & vbLf & errRec.FormatText
	End If
	Fail message
End Sub

Sub Fail(message)
	Wscript.Echo message
	Wscript.Quit 2
End Sub
'' --------------------------------------------------------------------------------------------------------------------------------------------------------------------
